package www.my.imageframecompare.VolleyConfig;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v4.util.LruCache;
import android.util.Log;

import com.android.volley.toolbox.ImageLoader.ImageCache;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


/**
 * 图片三级缓存方案
 * Creator 杨杰 2015/9/25.
 */
public class BitmapCache implements ImageCache {

	private static LruCache<String, Bitmap> mMemoryCache;//内存缓存核心类
	private DiskLruCache mDiskLruCache;//硬盘缓存核心类

	public BitmapCache(Context context) {
		int maxMemory = (int) Runtime.getRuntime().maxMemory();
		int cacheSize = maxMemory / 8;// 设置图片缓存大小为程序最大可用内存的1/8
		mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
			@Override
			protected int sizeOf(String key, Bitmap bitmap) {
				return bitmap.getRowBytes()*bitmap.getHeight();
			}
		};
		try {
			// 获取图片缓存路径
			File cacheDir = getDiskCacheDir(context, "bitmap");
			if (!cacheDir.exists()) {
				cacheDir.mkdirs();
			}
			// 创建DiskLruCache实例，初始化缓存数据
			mDiskLruCache = DiskLruCache
					.open(cacheDir, getAppVersion(context), 1, 20 * 1024 * 1024);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void  close(){
		try {
			this.mDiskLruCache.close();
		} catch (IOException e) {

		}
	}

	public void flush(){
		try {
			this.mDiskLruCache.flush();
		} catch (IOException e) {
		}
	}

	@Override
	public Bitmap getBitmap(String url) {
		//MD5加密url
		String key = hashKeyForDisk(url);
		//从内存中查找，如果没有的话从硬盘中查找
		Bitmap bitmap = mMemoryCache.get(key);
		if(bitmap == null){
			FileDescriptor fileDescriptor = null;
			FileInputStream fileInputStream = null;
			try {
				DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
				if (snapShot != null) {
					fileInputStream = (FileInputStream)snapShot.getInputStream(0);
					fileDescriptor = fileInputStream.getFD();
					if (fileDescriptor != null) {
						bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
						Log.v("Cache", "硬盘中找到了");
					}
				}else{
					Log.v("Cache", "硬盘没找到");
				}
			} catch (IOException e) {
				e.printStackTrace();
				Log.v("Cache", "没有找到");
				return null;
			}
		}else{
			Log.v("Cache", "内存中找到了");
		}
		return bitmap;
	}

	@Override
	public void putBitmap(String url, Bitmap bitmap) {
		//MD5加密url
		String key = hashKeyForDisk(url);
		//写入内存
		if(mMemoryCache.get(key) == null){
			mMemoryCache.put(key,bitmap);
			Log.v("Cache", "执行了put内存:" + key);
		}
		//写入硬盘
		OutputStream outputStream = null;
		try {
			if(mDiskLruCache.get(key) == null) {
				DiskLruCache.Editor editor = mDiskLruCache.edit(key);
				if (editor != null) {
					outputStream = editor.newOutputStream(0);
					if (url.endsWith("jpg") || url.endsWith("JPG") || url.endsWith("jpeg") || url.endsWith("JPEG")) {
						bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
						Log.v("Cache", "成功写入硬盘缓存:jpg");
					} else if (url.endsWith("png") || url.endsWith("PNG")) {
						bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
						Log.v("Cache", "成功写入硬盘缓存:png");
					} else {
						bitmap.compress(Bitmap.CompressFormat.WEBP, 100, outputStream);
						Log.v("Cache", "成功写入硬盘缓存:webp");
					}
					editor.commit();
					Log.v("Cache", "成功写入硬盘缓存");
					mDiskLruCache.flush();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if(outputStream != null){
					outputStream.close();
				}
			} catch (IOException e) {

			}
		}
	}

	/**
	 * 根据传入的uniqueName获取硬盘缓存的路径地址。
	 */
	public static File getDiskCacheDir(Context context, String uniqueName) {
		String cachePath;
		if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
				|| !Environment.isExternalStorageRemovable()) {
			cachePath = context.getExternalCacheDir().getPath();
		} else {
			cachePath = context.getCacheDir().getPath();
		}
		return new File(cachePath + File.separator + uniqueName);
	}

	/**
	 * 获取当前应用程序的版本号。
	 */
	public int getAppVersion(Context context) {
		try {
			PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(),
					0);
			return info.versionCode;
		} catch (PackageManager.NameNotFoundException e) {
			e.printStackTrace();
		}
		return 1;
	}

	/**
	 * 使用MD5算法对传入的key进行加密并返回。
	 */
	public String hashKeyForDisk(String key) {
		String cacheKey;
		try {
			final MessageDigest mDigest = MessageDigest.getInstance("MD5");
			mDigest.update(key.getBytes());
			cacheKey = bytesToHexString(mDigest.digest());
		} catch (NoSuchAlgorithmException e) {
			cacheKey = String.valueOf(key.hashCode());
		}
		return cacheKey;
	}

	private String bytesToHexString(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < bytes.length; i++) {
			String hex = Integer.toHexString(0xFF & bytes[i]);
			if (hex.length() == 1) {
				sb.append('0');
			}
			sb.append(hex);
		}
		return sb.toString();
	}
}